var tgd = tgd || {};
tgd.Tools = tgd.Tools || {};
tgd.Tools.ContactDiff = tgd.Tools.ContactDiff || {};

/*
 * model
 */
tgd.Tools.ContactDiff.Model = function () {

    var _currentContacts = null;
    var _currentGroups = null;

    var _users;
    var _contacts;
    var _exceptions = [
        "category",
        "link",
        "gd$etag",
        "content",
        "id",
        "updated",
        "app$edited",
        "xmlns",
        "xmlns$openSearch",
        "xmlns$gContact",
        "xmlns$batch",
        "xmlns$gd"
    ];

    this.__defineGetter__("Contacts", function() { return _contacts; });
    this.__defineGetter__("Users", function() { return _users; });
    this.__defineGetter__("Finished", function() { return _currentContacts !== null && _currentGroups !== null; });

    /*
     * TODO: better comment
     * returns a contact based on the googEntry.
     * contacts are compared on "title.$t"
     * if a contact already exists it is returned
     * otherwise a new contact is created and added
     */
    this._addNewAndGetContact = function(googEntry) {
        var current = null;

        for (var i = 0; i < _contacts.length; ++i) {
            if (googEntry.title.$t !== "" && _contacts[i].Name === googEntry.title.$t) {
                current = _contacts[i];
                break;
            }
        }

        //The contact (googEntry) does not exist, create a new one
        if (!current) {
            var newContact = new tgd.Tools.ContactDiff.Contact(googEntry.title.$t, function() { return _users; });
            _contacts.push(newContact);
            return newContact;
        } else {
            return current;
        }
    }

    /*
     *
     */
    this._load = function() {
        _users = [];
        _contacts = [];
        var key;

        for (var i = 0; i < localStorage.length; ++i) {
            key = localStorage.key(i);
            if (key.match(/@gmail\.com$/) !== null) {
                var entries = JSON.parse(localStorage.getItem(key));
                var u = new tgd.Tools.ContactDiff.User(key, entries);
                _users.push(u);

                for (var j = 0; j < entries.length; ++j) {
                    var entry = entries[j];
                    var c = this._addNewAndGetContact(entry);
                    c.add(u, entry);
                    u.add(c);
                }
            }
        }
        
        _users = _users.sort( function(a, b) { return a.Name.localeCompare(b.Name); } );
        _contacts = _contacts.sort( function(a, b) { return a.Name.localeCompare(b.Name); } );
    }

    this._load();

    /*
     * Strip the functions, recursive properties, primary properties, and exceptions so JSON.stringify can be used
     */
    this._cleanObject = function(o, path) {
        for (var i in o) {
            if (i === "rel" && o.rel !== undefined) {
                o.rel = o.rel.replace("http://schemas.google.com/g/2005#", "");
            }

            if (typeof o[i] === "function" || i === "$service_" || i === "primary" || _exceptions.some(function(element, index, array) { return element === (path + (path === "" ? "" : ".") + i); })) {
                o[i] = undefined;
            } else if (o[i] instanceof Array && o[i].length === 0) {
                o[i] = undefined;
            } else if (typeof o[i] === "object") {
                o[i] = this._cleanObject(o[i], (path + (path === "" ? "" : ".") + i));
            }
        }

        return o;
    }

    /*
     * Update contacts with group names instead of group "id".
     * TODO: rename
     */
    this._updateGroups = function(email) {
        if (_currentContacts !== null && _currentGroups !== null) {
            for (var i = 0; i < _currentContacts.length; ++i) {
                _currentContacts[i] = this._cleanObject(_currentContacts[i], "");
            }

            for (var i = 0; i < _currentContacts.length; ++i) {
                if (_currentContacts[i].gContact$groupMembershipInfo !== undefined) {
                    for (var j = 0; j < _currentContacts[i].gContact$groupMembershipInfo.length; ++j) {
                        for (var k = 0; k < _currentGroups.length; ++k) {
                            if (_currentContacts[i].gContact$groupMembershipInfo[j].href === _currentGroups[k].id.$t) {
                                _currentContacts[i].gContact$groupMembershipInfo[j].href = _currentGroups[k].title.$t;
                                break;
                            }
                        }
                    }
                }
            }

            localStorage.setItem(email, JSON.stringify(_currentContacts));
            this._load();
        }
    }

    /*
     * googleData - response object from google
     */
    this.add = function(googleData) {
        if (googleData.feed.category[0].term.match(/contact$/) !== null) {
            _currentContacts = googleData.feed.entry;
        } else if (googleData.feed.category[0].term.match(/group$/) !== null) {
            _currentGroups = googleData.feed.entry;
        } else {  //this should never happen
            console.dir(googleData);
            throw new Error("Check response from Google.");
        }

        this._updateGroups(googleData.feed.id.$t);
    }
    
    /*
     * Clear all data from localStorage.
     * email - optional - String - If given, erase the data for the given user.
     * 
     */
    this.eraseData = function(email) {
        if (email === undefined) {
            localStorage.clear();
        } else {
            localStorage.removeItem(email);
        }
    }
}
